/* tripl/include/tripl/tripl.h 
 * 
 * This file is part of tripl. 
 * 
 * tripl is free software: you can redistribute it and/or modify 
 * it under the terms of the GNU General Public License as published by 
 * the Free Software Foundation, either version 3 of the License, or 
 * (at your option) any later version. 
 * 
 * tripl is distributed in the hope that it will be useful, 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
 * GNU General Public License for more details. 
 * 
 * You should have received a copy of the GNU General Public License 
 * along with tripl. If not, see <https://www.gnu.org/licenses/>
 */ 




#ifndef __TRIPL_H__
#define __TRIPL_H__


#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>


#define panic(msg, ...) 	error(msg, ##__VA_ARGS__); exit(1)

#define BUG_ON(cond) 		({if (unlikely(cond)) panic(__FUNCTION__ ": " #cond)})

/* macros to let you know, what does it do */

#define __arch 
#define __arch_templ 

/* low level assembly: never read */
#define __ll_asm 
#define __init 


#define FG_BLACK 		30
#define FG_RED 			31
#define FG_GREEN 		32
#define FG_YELLOW 		33
#define FG_BLUE 		34
#define FG_WHITE 		37
#define FG_LIGHTBLUE 		36

#define BG_BLACK 		40
#define BG_RED 			41
#define BG_GREEN 		42
#define BG_YELLOW 		43
#define BG_BLUE 		44
#define BG_WHITE 		47

#define MODE_DEF 		0
#define MODE_HIGHLIGHT 		1
#define MODE_LINE 		4

#define MAKECOMPILERHAPPY 	114514


#define ansi_csi_st(strm, m, fg, bg) \
	fprintf(strm, "\033[%d;%d;%dm", m, fg, bg)

#define ansi_csi_ed(strm)	fprintf(strm, "\033[0m")


#define error(msg, ...) \
	do { \
	ansi_csi_st(stderr, MODE_HIGHLIGHT, FG_WHITE, BG_BLACK); \
	fprintf(stderr, "tripl: "); \
	ansi_csi_ed(stderr); \
	ansi_csi_st(stderr, MODE_HIGHLIGHT, FG_RED, BG_BLACK); \
	fprintf(stderr, msg, ##__VA_ARGS__); \
	ansi_csi_ed(stderr); \
	fprintf(stderr, "\n"); \
	} while (0)


/* oh no, isdigit() is a function :-( */
// #define isnr(c) 	isdigit(c)
#define isnr(c) 	((c) >= '0' && (c) <= '9')
#define ischr(c)	(((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
#define _skip_spaces(s) while (isspace(*(s))) (s)++; if (*(s) == '\n') lno++;
#define skip_spaces() 	_skip_spaces(line_buffer);
#define _skip_word(s) 	while (!isspace(*(s))) (s)++; _skip_spaces(s)

/* okay, it's a wrong thing itoa, should be atoi... */
#define itoa(c) 	((c) - '0')
#define atox(c) 	((c) >= 'a' ? (c) - 'a' + 10 : (c) - '0')
#define atoX(c) 	((c) >= 'A' ? (c) - 'A' + 10 : (c) - '0')

#define arrlen(arr) 	(sizeof(arr) / sizeof(arr[0]))
#define boolean(__c) 	(!!(__c))
#define likely(__c) 	__builtin_expect(boolean(__c), 1)
#define unlikely(__c) 	__builtin_expect(boolean(__c), 0)


#define __push_nr(__stack, nr, np, mask) ({ \
	struct klist_node *p = malloc(sizeof(struct klist_node)); \
	klist_init(p); \
	p->value = nr; \
	p->payload = np; \
	p->xmask = mask; \
	klist_add(__stack, p); \
})

#define __pop_nr(__stack, nr) ({ \
	struct klist_node *p = (__stack)->prev; \
	int __nr = p->value; \
	klist_del(__stack, p); \
	free(p); \
	__nr; \
})


/* warning that np must be allocated by malloc or 0, not on stack */
#define push_nr(nr, np, mask) 	__push_nr(&stack, nr, np, mask)
#define _pop_nr(nr) 		__pop_nr(&stack, nr)


#define WORDTYPE_INVAL 	0
#define WORDTYPE_KWORD 	1
#define WORDTYPE_NR 	2
#define WORDTYPE_NAME 	3
#define WORDTYPE_STR 	4


#define DECLARE_FN 		0x80000000
#define DECLARE_VAR 		0x40000000
#define DECLARE_NOARG	 	0x00002000

/* only declared, so will not raise name-already-defined */
#define XMASK_WEAK 		0x80000000
#define XMASK_FN 		0x40000000


/* main.c */
extern char 			*fname;
extern int 			lno;
extern char 			*eof;
extern char 			*linebuffer_save;

#define arg_init(a) 		(a)->arg_s = NULL; (a)->arg_v = 0; \
				(a)->next = (a); (a)->prev = (a);

struct arg_entry {
	char 			*arg_s;
	long 			arg_v;

	struct arg_entry 	*next, *prev;
};

struct condition {
	char 			*namea, *nameb;
	int 			nra, nrb;
};


struct attr_table {
	char 			*attrname;
	int 			attrmask;
};


extern const struct attr_table vardef_attrtab[];
extern const struct attr_table declare_attrtab[];
extern const struct attr_table dump_attrtab[];


int do_tripl_compile(char *, off_t);

char *getword(char *fbuffer, int *type, int *out);
char *read_code_block(char *p);
int getattrmask(char *p, const struct attr_table *tab);
int generic_error(char *msg, char *line, int lno);

extern struct context *current;


#endif

